package cn.magic.basic.service.impl;

import cn.magic.basic.constants.BaseConstants;
import cn.magic.basic.dto.SmsCodeDto;
import cn.magic.basic.exception.BusinessException;
import cn.magic.basic.service.IVerifyCodeService;
import cn.magic.basic.utils.StrUtils;
import cn.magic.basic.utils.VerifyCodeUtils;
import cn.magic.user.domain.User;
import cn.magic.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
* @Description: 获取图形验证码业务层
* @Author: Mr.pc
* @Version: 1.0
* @Date:  2022/7/4 18:17
*/
@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;


    /**
    * @Title: getImageCode
    * @Description: 获取图形验证码
    * @Author: Mr.pc
    * @Version: 1.0
    * @Date:  2022/7/4 18:17
    * @Parameters: [imageCodeKey]
    * @Return java.lang.String
    */
    @Override
    public String getImageCode(String imageCodeKey) {
        // 判断参数是否为空
        if (StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("参数不能为空");
        }
        // 获取到随机4为的字符串
        String imageCode = StrUtils.getComplexRandomString(4);
        // 使用工具类生成Base64图形验证码
        String imageBase64Str = VerifyCodeUtils.VerifyCode(110, 40, imageCode);
        // 根据key和value 保存到Redis中，并设置5分钟有效期
        redisTemplate.opsForValue().set(imageCodeKey,imageCode,5, TimeUnit.MINUTES);

        return imageBase64Str;
    }


    /**
    * @Title: smsCode
    * @Description: 获取手机验证码
    * @Author: Mr.pc
    * @Version: 1.0
    * @Date:  2022/7/6 13:01
    * @Parameters: [smsCodeDto]
    * @Return void
    */
    @Override
    public void smsCode(SmsCodeDto smsCodeDto) {
       /* // 获取用户填写的图形验证码的值
        String imageCodeValue = smsCodeDto.getImageCodeValue();
        // 获取前端传递的图形验证码的key值
        String imageCodeKey = smsCodeDto.getImageCodeKey();*/
        // 获取电话
        String phone = smsCodeDto.getPhone();
        // 获取业务类型的type
        String type = smsCodeDto.getType();
        // 1.非空判断
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)){
            throw new BusinessException("参数不能为空");
        }
        // 判断走哪个业务
        // 注册业务
        if ("register".equals(type)){
            // 校验图形验证码是否正确
            checkImageCode(smsCodeDto);
            // 3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.loadByphone(phone);
            if (user != null){
                throw new BusinessException("用户已经注册，请直接登录，如果忘记密码，请点击忘记密码找回");
            }
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_KEY,phone);

        } else if ("binder".equals(type)){
            // 微信绑定业务 发送短信验证码
            sendCode(BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_KEY,phone);


        }

       /* // 2.判断两次手机号是否一致，业务键+手机号拼接后去Redis中获取value，如果没有，说明要么不一致，要么过期了，那就提示重新获取
        // 判断手机验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        // 只要他不为null，就表示存在，如果为null，表示不存在或者过期
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请从新输入");
        }
        // 忽略大小写比较手机验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码不正常，请从新输入");
        }
        // 3.判断用户是否已注册，如果已注册提示用户
       User user = userMapper.loadByphone(phone);
        if (user != null){
            throw new BusinessException("用户已经注册，请直接登录，如果忘记密码，请点击忘记密码找回");
        }*/
      /*  //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_KEY + phone;
        Object phoneCodeKeyValue = redisTemplate.opsForValue().get(phoneCodeKey);

        String phoneCode = "";
        // 当phoneCodeKeyValue不存在时，
        if (phoneCodeKeyValue == null){
            // 生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {
            // 如果存在
            // 1.分割value得到时间戳，跟现在的时间
            // 戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeKeyValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取");
            }
            // 将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey,phoneCodeRedis,3,TimeUnit.MINUTES);
        // 发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);*/

    }

    /** 
    * @Title: sendCode
    * @Description: 发送手机验证码
    * @Author: Mr.pc
    * @Version: 1.0
    * @Date:  2022/7/10 19:32  
    * @Parameters: [businessKey, phone]
    * @Return void
    */
    public void sendCode(String businessKey, String phone){
        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = businessKey + phone;
        Object phoneCodeKeyValue = redisTemplate.opsForValue().get(phoneCodeKey);

        String phoneCode = "";
        // 当phoneCodeKeyValue不存在时，
        if (phoneCodeKeyValue == null){
            // 生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {
            // 如果存在
            // 1.分割value得到时间戳，跟现在的时间
            // 戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeKeyValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取");
            }
            // 将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey,phoneCodeRedis,3,TimeUnit.MINUTES);
        // 发送短信验证码
        // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
        System.out.println("亲，您的验证码是："+ phoneCode);

    }

    /** 
    * @Title: checkImageCode
    * @Description: 校验图形验证码
    * @Author: Mr.pc
    * @Version: 1.0
    * @Date:  2022/7/10 19:37  
    * @Parameters: [smsCodeDto]
    * @Return void
    */
    public void checkImageCode(SmsCodeDto smsCodeDto){
        // 图形验证码的key
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = smsCodeDto.getImageCodeValue();
        //1.非空校验
        if (StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数不能为空！");
        }
        // 2.判断两次手机号是否一致，业务键+手机号拼接后去Redis中获取value，如果没有，说明要么不一致，要么过期了，那就提示重新获取
        // 判断手机验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        // 只要他不为null，就表示存在，如果为null，表示不存在或者过期
        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请从新输入");
        }
        // 忽略大小写比较手机验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码不正常，请从新输入");
        }
    }
}
